﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using PersonaLibrary.Commands.CommandsForTotalItems;
using PersonaLibrary.Data;
using PersonaLibrary.Data.ServiceReference;
using PersonaLibrary.ViewModel.CollectionViewModel;

namespace PersonaLibrary.ViewModel
{
	internal class BaseCollectionViewModel<TEntity> : UserControlViewModel, ICollectionViewModel
		where TEntity : class, IDBEntity
	{
		private Dictionary<string, string> _orderProperties;
		private ListCollectionViewWrapper _collection;
		private bool _inSearched;

		#region Private commands

		private RelayCommand _resetCommand;
		private RelayCommand _orderCommand;

		#endregion

		#region Public commands

		public RelayCommand ResetCommand
		{
			get
			{
				if (_resetCommand == null) _resetCommand = new RelayCommand(param => ResetCurrentOperation(), param => true);
				return _resetCommand;
			}
		}

		public RelayCommand OrderCommand
		{
			get
			{
				if (_orderCommand == null)
					_orderCommand = new RelayCommand(x => Order(x.ToString()), x => true);

				return _orderCommand;
			}
		}

		#endregion

		protected BaseCollectionViewModel()
		{
			Context = new DataServiceContextWrapper();
			
			FillOrderProperties();

			ObservableCollection = new ObservableCollection<TEntity>();
		}

		protected virtual void CollectionLoad()
		{
		}

		protected DataServiceContextWrapper Context { set; get; }

		protected ObservableCollection<TEntity> ObservableCollection { set; get; }

		protected virtual void LinqToDbDataContextItemUpdated(BaseEntity obj)
		{
			List<TEntity> items = ObservableCollection.Where(x => x.Id == obj.Id).ToList();

			foreach (var item in items)
			{
				int index = ObservableCollection.IndexOf(item);
				ObservableCollection[index] = obj as TEntity;
			}

			RisePropertyChanged("Collection");
		}

		protected virtual void LinqToDbDataContextItemDeleted(BaseEntity obj)
		{
			if (obj is TEntity && ObservableCollection.Any(x => x.Id == obj.Id))
				ObservableCollection.Remove(ObservableCollection.Single(x => x.Id == obj.Id));
		}

		protected virtual void LinqToDbDataContextItemAdded(BaseEntity obj)
		{
			if (obj is TEntity && !ObservableCollection.Contains((IDBEntity)obj))
				ObservableCollection.Add(obj as TEntity);
		}

		public TEntity SelectItem
		{
			set
			{
				if (value != null)
				{
					string viewmodelType = string.Format("PersonaLibrary.ViewModel.{0}ViewModel.{0}ViewModel, PersonaLibrary",
														 typeof(TEntity).Name);
					IViewModel viewModel = (IViewModel)Activator.CreateInstance(Type.GetType(viewmodelType), value.Id);
					CurrentApplication.AddViewModel(viewModel);
				}
			}
		}

		public ListCollectionViewWrapper Collection
		{
			get
			{
				if (_collection == null)
					_collection = new ListCollectionViewWrapper(ObservableCollection);
				return _collection;
			}
		}

		public ICommandsPack CurrentPack
		{
			get { return CommandsPackStrategy.Interop[typeof(TEntity)]; }
		}

		public Dictionary<string, string> OrderProperties
		{
			get
			{
				return _orderProperties;
			}
			private set
			{
				_orderProperties = value;
				RisePropertyChanged("OrderProperties");
			}
		}

		public bool InSearched
		{
			private set
			{
				_inSearched = value;
				RisePropertyChanged("InSearched");
			}
			get
			{
				return _inSearched;
			}
		}

		private void ResetCurrentOperation()
		{
			InSearched = false;
		}

		private void Order(string property)
		{
			_collection.SortDescriptions.Clear();
			Stopwatch sortTimer = Stopwatch.StartNew();
			_collection.SortDescriptions.Add(new SortDescription(property, ListSortDirection.Ascending));
			sortTimer.Stop();
			Debug.WriteLine("Sort time " + sortTimer.Elapsed);
		}

		private void FillOrderProperties()
		{
			Dictionary<string, string> result = new Dictionary<string, string>();

			List<Metadata.Point> points = Metadata.Instance[typeof(TEntity).Name];
			if (points != null)
			{
				foreach (Metadata.Point point in points.Where(x => x.IsOrder))
				{
					result.Add(point.Name, point.RuName);
				}
			}

			OrderProperties = result;
		}

		public override string ToString()
		{
			return string.Concat("Список ", CollectionNameHelper.ResolveNameForCollection(typeof(TEntity).Name));
		}
	}
}
